home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tar.gnu / sprite / RCS / extract.c,v < prev    next >
Encoding:
Text File  |  1992-03-29  |  31.0 KB  |  1,350 lines

  1. head     1.6;
  2. branch   ;
  3. access   ;
  4. symbols  ;
  5. locks    ; strict;
  6. comment  @ * @;
  7.  
  8.  
  9. 1.6
  10. date     92.03.28.17.31.54;  author kupfer;  state Exp;
  11. branches ;
  12. next     1.5;
  13.  
  14. 1.5
  15. date     92.03.05.21.45.59;  author kupfer;  state Exp;
  16. branches ;
  17. next     1.4;
  18.  
  19. 1.4
  20. date     91.04.25.21.01.56;  author jhh;  state Exp;
  21. branches ;
  22. next     1.3;
  23.  
  24. 1.3
  25. date     90.10.27.17.56.19;  author rab;  state Exp;
  26. branches ;
  27. next     1.2;
  28.  
  29. 1.2
  30. date     90.06.28.15.35.32;  author rab;  state Exp;
  31. branches ;
  32. next     1.1;
  33.  
  34. 1.1
  35. date     90.03.21.22.37.12;  author rab;  state Exp;
  36. branches ;
  37. next     ;
  38.  
  39.  
  40. desc
  41. @@
  42.  
  43.  
  44. 1.6
  45. log
  46. @Restructure to remove some of the ALLOW_LONG_NAMES ifdefs.  Fix to
  47. allow both a long file name and a long link name.  Check for Posix
  48. archives.
  49. @
  50. text
  51. @/* Extract files from a tar archive.
  52.    Copyright (C) 1988 Free Software Foundation
  53.  
  54. This file is part of GNU Tar.
  55.  
  56. GNU Tar is free software; you can redistribute it and/or modify
  57. it under the terms of the GNU General Public License as published by
  58. the Free Software Foundation; either version 1, or (at your option)
  59. any later version.
  60.  
  61. GNU Tar is distributed in the hope that it will be useful,
  62. but WITHOUT ANY WARRANTY; without even the implied warranty of
  63. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  64. GNU General Public License for more details.
  65.  
  66. You should have received a copy of the GNU General Public License
  67. along with GNU Tar; see the file COPYING.  If not, write to
  68. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  69.  
  70. /*
  71.  * Extract files from a tar archive.
  72.  *
  73.  * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  74.  *
  75.  * @@(#) extract.c 1.32 87/11/11 - gnu
  76.  */
  77.  
  78. #include <stdio.h>
  79. #include <errno.h>
  80. #include <sys/types.h>
  81. #include <sys/stat.h>
  82. #include <sys/param.h>
  83.  
  84. #ifdef BSD42
  85. #include <sys/file.h>
  86. #endif
  87.  
  88. #ifdef USG
  89. #include <fcntl.h>
  90. #endif
  91.  
  92. #ifdef    MSDOS
  93. #include <fcntl.h>
  94. #endif    /* MSDOS */
  95.  
  96. /*
  97.  * Some people don't have a #define for these.
  98.  */
  99. #ifndef    O_BINARY
  100. #define    O_BINARY    0
  101. #endif
  102. #ifndef O_NDELAY
  103. #define    O_NDELAY    0
  104. #endif
  105.  
  106. #ifdef NO_OPEN3
  107. /* We need the #define's even though we don't use them. */
  108. #include "open3.h"
  109. #endif
  110.  
  111. #ifdef EMUL_OPEN3
  112. /* Simulated 3-argument open for systems that don't have it */
  113. #include "open3.h"
  114. #endif
  115.  
  116. extern int errno;            /* From libc.a */
  117. extern time_t time();            /* From libc.a */
  118. extern char *index();            /* From libc.a or port.c */
  119.  
  120. #include "tar.h"
  121. #include "port.h"
  122.  
  123. extern FILE *msg_file;
  124.  
  125. extern union record *head;        /* Points to current tape header */
  126. extern struct stat hstat;        /* Stat struct corresponding */
  127. extern int head_standard;        /* Tape header is in ANSI format */
  128.  
  129. extern char *save_name;
  130. extern long save_totsize;
  131. extern long save_sizeleft;
  132.  
  133. extern void print_header();
  134. extern void skip_file();
  135. extern void skip_extended_headers();
  136. extern void pr_mkdir();
  137.  
  138. int make_dirs();            /* Makes required directories */
  139.  
  140. static time_t now = 0;            /* Current time */
  141. static we_are_root = 0;            /* True if our effective uid == 0 */
  142. static int notumask = ~0;        /* Masks out bits user doesn't want */
  143.  
  144. /*
  145.  * "Scratch" space to store the information about a sparse file before
  146.  * writing the info into the header or extended header
  147.  */
  148. /*struct sp_array    *sparsearray;*/
  149.  
  150. /* number of elts storable in the sparsearray */
  151. /*int    sp_array_size = 10;*/
  152.  
  153. /*
  154.  * Set up to extract files.
  155.  */
  156. extr_init()
  157. {
  158.     int ourmask;
  159.  
  160.     now = time((time_t *)0);
  161.     if (geteuid() == 0)
  162.         we_are_root = 1;
  163.  
  164.     /*
  165.      * We need to know our umask.  But if f_use_protection is set,
  166.      * leave our kernel umask at 0, and our "notumask" at ~0.
  167.      */
  168.     ourmask = umask(0);        /* Read it */
  169.     if (!f_use_protection) {
  170.         (void) umask (ourmask);    /* Set it back how it was */
  171.         notumask = ~ourmask;    /* Make umask override permissions */
  172.     }
  173. }
  174.  
  175.  
  176. /*
  177.  * Extract a file from the archive.
  178.  */
  179. void
  180. extract_archive()
  181. {
  182.     register char *data;
  183.     int fd, check, namelen, written, openflag;
  184.     long size;
  185.     time_t acc_upd_times[2];
  186.     register int skipcrud;
  187.     register int i;
  188.     int sparse_ind = 0;
  189.     union record *exhdr;    
  190.     int end_nulls;
  191.  
  192.     sp_array_size = 10;
  193.     decode_header(head, &hstat, &head_standard, 1);    /* Snarf fields */
  194.  
  195.     if(f_confirm && !confirm("extract",current_filename)) {
  196.         if (gnu_extended_header(head))
  197.             skip_extended_headers();
  198.         skip_file((long)hstat.st_size);
  199.         return;
  200.     }
  201.  
  202.     /* Print the record from 'head' and 'hstat' */
  203.     if (f_verbose)
  204.         print_header();
  205.  
  206.     /*
  207.      * Check for fully specified pathnames and other atrocities.
  208.      *
  209.      * Note, we can't just make a pointer to the new file name,
  210.      * since saverec() might move the header and adjust "head".
  211.      * We have to start from "head" every time we want to touch
  212.      * the header record.
  213.      */
  214.     skipcrud = 0;
  215.     while (!f_absolute_paths && '/' == current_filename[skipcrud]) {
  216.         static int warned_once = 0;
  217.  
  218.         skipcrud++;    /* Force relative path */
  219.         if (!warned_once++) {
  220.             msg("Removing leading / from absolute path names in the archive.");
  221.         }
  222.     }
  223.  
  224.     sparsearray = (struct sp_array *) malloc(sp_array_size * sizeof(struct sp_array));
  225.     switch (head->header.linkflag) {
  226.  
  227.     default:
  228.         msg("Unknown file type '%c' for %s, extracted as normal file",
  229.             head->header.linkflag, skipcrud+current_filename);
  230.         /* FALL THRU */
  231.  
  232.     /* 
  233.      * JK - What we want to do if the file is sparse is loop through
  234.      * the array of sparse structures in the header and read in
  235.      * and translate the character strings representing  1) the offset
  236.      * at which to write and 2) how many bytes to write into numbers,
  237.      * which we store into the scratch array, "sparsearray".  This
  238.      * array makes our life easier the same way it did in creating
  239.      * the tar file that had to deal with a sparse file.
  240.      *
  241.      * After we read in the first five (at most) sparse structures,
  242.      * we check to see if the file has an extended header, i.e., 
  243.      * if more sparse structures are needed to describe the contents
  244.      * of the new file.  If so, we read in the extended headers
  245.      * and continue to store their contents into the sparsearray.
  246.      */
  247.     case LF_SPARSE:
  248.         for (i = 0; i < SPARSE_IN_HDR; i++) {
  249.             if (!head->header.sp[i].numbytes)
  250.                 break;
  251.             sparsearray[i].offset = 
  252.                 from_oct(1+12, head->header.sp[i].offset);
  253.             sparsearray[i].numbytes = 
  254.                 from_oct(1+12, head->header.sp[i].numbytes);
  255.         }
  256.  
  257. /*        end_nulls = from_oct(1+12, head->header.ending_blanks);*/
  258.  
  259.         if (gnu_extended_header(head) &&
  260.             (head->header.isextended & XH_SPARSE_FILE)) {
  261.             /* read in the list of extended headers
  262.                and translate them into the sparsearray 
  263.                as before */
  264.  
  265.             static int ind = SPARSE_IN_HDR;
  266.  
  267.             for (;;) {
  268.  
  269.                 exhdr = findrec();
  270.                 for (i = 0; i < SPARSE_EXT_HDR; i++) {
  271.  
  272.                     if (i+ind > sp_array_size-1) {
  273.                     /*
  274.                      * realloc the scratch area
  275.                      * since we've run out of room --
  276.                      */
  277.                         sparsearray = (struct sp_array *) 
  278.                                 realloc(sparsearray,
  279.                                 2 * sp_array_size * (sizeof(struct sp_array)));
  280.                         sp_array_size *= 2;
  281.                     }
  282.                     if (!exhdr->ext_hdr.xh_sp[i].numbytes)
  283.                         break;
  284.                     sparsearray[i+ind].offset = 
  285.                         from_oct(1+12, exhdr->ext_hdr.xh_sp[i].offset);
  286.                     sparsearray[i+ind].numbytes = 
  287.                         from_oct(1+12, exhdr->ext_hdr.xh_sp[i].numbytes);
  288.                 }
  289.                 if (!exhdr->ext_hdr.xh_isextended) 
  290.                     break;
  291.                 else {
  292.                     ind += SPARSE_EXT_HDR;
  293.                     userec(exhdr);
  294.                 }
  295.             }
  296.             userec(exhdr);
  297.         }
  298.  
  299.         /* FALL THRU */
  300.     case LF_OLDNORMAL:
  301.     case LF_NORMAL:
  302.     case LF_CONTIG:
  303.  
  304.         /*
  305.          * Appears to be a file.
  306.          * See if it's really a directory.
  307.          */
  308.         namelen = strlen(skipcrud+current_filename)-1;
  309.         if (current_filename[skipcrud+namelen] == '/')
  310.             goto really_dir;
  311.  
  312.         /* FIXME, deal with protection issues */
  313.     again_file:
  314.         openflag = (f_keep?
  315. #ifdef sprite
  316.             /*
  317.              * Currently, a bug in the sprite file system makes
  318.              * opening regular files with O_NDELAY a bad idea.
  319.              * Writes fail with EWOULDBLOCK when local cache
  320.              * fills.
  321.              */
  322.             O_BINARY|O_WRONLY|O_CREAT|O_EXCL:
  323.             O_BINARY|O_WRONLY|O_CREAT|O_TRUNC)
  324. #else
  325.             O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_EXCL:
  326.             O_BINARY|O_NDELAY|O_WRONLY|O_CREAT|O_TRUNC)
  327. #endif
  328.             | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);            
  329.             /*
  330.              * JK - The last | is a kludge to solve the problem
  331.              * the O_APPEND flag  causes with files we are
  332.              * trying to make sparse:  when a file is opened
  333.              * with O_APPEND, it writes  to the last place
  334.              * that something was written, thereby ignoring
  335.              * any lseeks that we have done.  We add this
  336.              * extra condition to make it able to lseek when
  337.              * a file is sparse, i.e., we don't open the new
  338.              * file with this flag.  (Grump -- this bug caused
  339.              * me to waste a good deal of time, I might add)
  340.                */
  341.  
  342.         if(f_exstdout) {
  343.             fd = 1;
  344.             goto extract_file;
  345.         }
  346. #ifdef O_CTG
  347.         /*
  348.          * Contiguous files (on the Masscomp) have to specify
  349.          * the size in the open call that creates them.
  350.          */
  351.         if (head->header.linkflag == LF_CONTIG)
  352.             fd = open(skipcrud+current_filename, openflag | O_CTG,
  353.                 hstat.st_mode, hstat.st_size);
  354.         else
  355. #endif
  356.         {
  357. #ifdef NO_OPEN3
  358.             /*
  359.              * On raw V7 we won't let them specify -k (f_keep), but
  360.              * we just bull ahead and create the files.
  361.              */
  362.             fd = creat(skipcrud+current_filename, hstat.st_mode);
  363. #else
  364.             /*
  365.              * With 3-arg open(), we can do this up right.
  366.              */
  367.             fd = open(skipcrud+current_filename, openflag, hstat.st_mode);
  368. #endif
  369.         }
  370.  
  371.         if (fd < 0) {
  372.             if (make_dirs(skipcrud+current_filename))
  373.                 goto again_file;
  374.             msg_perror("Could not create file %s",skipcrud+current_filename);
  375.             if (gnu_extended_header(head))
  376.                 skip_extended_headers();
  377.             skip_file((long)hstat.st_size);
  378.             goto quit;
  379.         }
  380.  
  381.     extract_file:
  382.         if (head->header.linkflag == LF_SPARSE) {
  383.             char    *name;
  384.             int    namelen;
  385.  
  386.             /*
  387.              * Kludge alert.  NAME is assigned to header.name
  388.              * because during the extraction, the space that
  389.              * contains the header will get scribbled on, and
  390.              * the name will get munged, so any error messages
  391.              * that happen to contain the filename will look
  392.              * REAL interesting unless we do this.
  393.              * (XXX or at least it used to be like this, before 
  394.              * get_names() was put in. -mdk)
  395.              */
  396.             namelen = strlen(skipcrud+current_filename);
  397.             name = (char *) malloc((sizeof(char)) * namelen);
  398.             bcopy(skipcrud+current_filename, name, namelen);
  399.             size = hstat.st_size;
  400.             extract_sparse_file(fd, &size, hstat.st_size,
  401.                          name);
  402.         }            
  403.         else         
  404.           for (size = hstat.st_size;
  405.                size > 0;
  406.                size -= written) {
  407.             if(f_multivol) {
  408.                 save_name=current_filename;
  409.                 save_totsize=hstat.st_size;
  410.                 save_sizeleft=size;
  411.             }
  412.             
  413.             /*
  414.              * Locate data, determine max length
  415.              * writeable, write it, record that
  416.              * we have used the data, then check
  417.              * if the write worked.
  418.              */
  419.             data = findrec()->charptr;
  420.             if (data == NULL) {    /* Check it... */
  421.                 msg("Unexpected EOF on archive file");
  422.                 break;
  423.             }
  424.             /*
  425.              * JK - If the file is sparse, use the sparsearray
  426.              * that we created before to lseek into the new
  427.              * file the proper amount, and to see how many
  428.              * bytes we want to write at that position.
  429.              */
  430. /*            if (head->header.linkflag == LF_SPARSE) {
  431.                 off_t pos;
  432.                 
  433.                 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
  434.                 printf("%d at %d\n", (int) pos, sparse_ind);
  435.                 written = sparsearray[sparse_ind++].numbytes;
  436.             } else*/
  437.             written = endofrecs()->charptr - data;
  438.             if (written > size)
  439.                 written = size;
  440.             errno = 0;
  441.             check = write(fd, data, written);
  442.             /*
  443.              * The following is in violation of strict
  444.              * typing, since the arg to userec
  445.              * should be a struct rec *.  FIXME.
  446.              */
  447.             userec((union record *)(data + written - 1));
  448.             if (check == written) continue;
  449.             /*
  450.              * Error in writing to file.
  451.              * Print it, skip to next file in archive.
  452.              */
  453.             if(check<0)
  454.                 msg_perror("couldn't write to file %s",skipcrud+current_filename);
  455.             else
  456.                 msg("could only write %d of %d bytes to file %s",written,check,skipcrud+current_filename);
  457.             skip_file((long)(size - written));
  458.             break;    /* Still do the close, mod time, chmod, etc */
  459.         }
  460.  
  461.         if(f_multivol)
  462.             save_name = 0;
  463.  
  464.             /* If writing to stdout, don't try to do anything
  465.                to the filename; it doesn't exist, or we don't
  466.                want to touch it anyway */
  467.         if(f_exstdout)
  468.             break;
  469.             
  470. /*        if (gnu_extended_header(head)) {
  471.             register union record *exhdr;
  472.             register int i;
  473.  
  474.             for (i = 0; i < 21; i++) {
  475.                 long offset;
  476.  
  477.                 if (!exhdr->ext_hdr.sp[i].numbytes)
  478.                     break;
  479.                 offset = from_oct(1+12,
  480.                         exhdr->ext_hdr.sp[i].offset);
  481.                 written = from_oct(1+12,
  482.                         exhdr->ext_hdr.sp[i].numbytes);
  483.                 lseek(fd, offset, 0);
  484.                 check = write(fd, data, written);
  485.                 if (check == written) continue;
  486.  
  487.             }
  488.  
  489.  
  490.         }*/
  491.         check = close(fd);
  492.         if (check < 0) {
  493.             msg_perror("Error while closing %s",skipcrud+current_filename);
  494.         }
  495.  
  496.  
  497.     set_filestat:
  498.  
  499.         /*
  500.          * If we are root, set the owner and group of the extracted
  501.          * file.  This does what is wanted both on real Unix and on
  502.          * System V.  If we are running as a user, we extract as that
  503.          * user; if running as root, we extract as the original owner.
  504.          */
  505.         if (we_are_root) {
  506.             if (chown(skipcrud+current_filename, hstat.st_uid,
  507.                   hstat.st_gid) < 0) {
  508.                 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+current_filename,hstat.st_uid,hstat.st_gid);
  509.             }
  510.         }
  511.  
  512.         /*
  513.          * If '-k' is not set, open() or creat() could have saved
  514.          * the permission bits from a previously created file,
  515.          * ignoring the ones we specified.
  516.          * Even if -k is set, if the file has abnormal
  517.          * mode bits, we must chmod since writing or chown() has
  518.          * probably reset them.
  519.          *
  520.          * If -k is set, we know *we* created this file, so the mode
  521.          * bits were set by our open().   If the file is "normal", we
  522.          * skip the chmod.  This works because we did umask(0) if -p
  523.          * is set, so umask will have left the specified mode alone.
  524.          */
  525.         if ((!f_keep)
  526.             || (hstat.st_mode & (S_ISUID|S_ISGID|S_ISVTX))) {
  527.             if (chmod(skipcrud+current_filename,
  528.                   notumask & (int)hstat.st_mode) < 0) {
  529.                 msg_perror("cannot change mode of file %s to %ld",skipcrud+current_filename,notumask & (int)hstat.st_mode);
  530.             }
  531.         }
  532.         /*
  533.          * Set the modified time of the file.
  534.          * 
  535.          * Note that we set the accessed time to "now", which
  536.          * is really "the time we started extracting files".
  537.          * unless f_gnudump is used, in which case .st_atime is used
  538.          */
  539.         if (!f_modified) {
  540.             /* fixme if f_gnudump should set ctime too, but how? */
  541.             if(f_gnudump) acc_upd_times[0]=hstat.st_atime;
  542.             else acc_upd_times[0] = now;             /* Accessed now */
  543.             acc_upd_times[1] = hstat.st_mtime; /* Mod'd */
  544.             if (utime(skipcrud+current_filename, acc_upd_times) < 0) {
  545.                 msg_perror("couldn't change access and modification times of %s",skipcrud+current_filename);
  546.             }
  547.         }
  548.  
  549.     quit:
  550.         break;
  551.  
  552.     case LF_LINK:
  553.     again_link:
  554.         check = link (current_linkname, skipcrud+current_filename);
  555.         if (check == 0)
  556.             break;
  557.         if (make_dirs(skipcrud+current_filename))
  558.             goto again_link;
  559.         if(f_gnudump && errno==EEXIST)
  560.             break;
  561.         msg_perror("Could not link %s to %s",
  562.             skipcrud+current_filename,current_linkname);
  563.         break;
  564.  
  565. #ifdef S_IFLNK
  566.     case LF_SYMLINK:
  567.     again_symlink:
  568.         check = symlink(current_linkname,
  569.                     skipcrud+current_filename);
  570.         /* FIXME, don't worry uid, gid, etc... */
  571.         if (check == 0)
  572.             break;
  573.         if (make_dirs(skipcrud+current_filename))
  574.             goto again_symlink;
  575.         msg_perror("Could not create symlink to %s",current_linkname);
  576.         break;
  577. #endif
  578.  
  579. #ifdef S_IFCHR
  580.     case LF_CHR:
  581.         hstat.st_mode |= S_IFCHR;
  582.         goto make_node;
  583. #endif
  584.  
  585. #ifdef S_IFBLK
  586.     case LF_BLK:
  587.         hstat.st_mode |= S_IFBLK;
  588.         goto make_node;
  589. #endif
  590.  
  591. #ifdef S_IFIFO
  592.     /* If local system doesn't support FIFOs, use default case */
  593.         case LF_FIFO:
  594. #ifdef sprite
  595.     again_fifo:
  596.         check = SpriteMakeNamedPipe(current_filename, &hstat);
  597.         if (check != 0) {
  598.             if (make_dirs(skipcrud+current_filename)) {
  599.             goto again_fifo;
  600.             }
  601.             msg_perror("Could not make named pipe %s",
  602.             skipcrud+current_filename);
  603.             break;
  604.         }
  605.         goto set_filestat;
  606. #else
  607.         hstat.st_mode |= S_IFIFO;
  608.         hstat.st_rdev = 0;        /* FIXME, do we need this? */
  609.         goto make_node;
  610. #endif /* sprite */
  611. #endif /* S_IFIFO */
  612.  
  613. #ifdef sprite
  614.     case LF_PSEUDODEV:
  615.     again_pdev:
  616.         check = SpriteMakePseudoDev(current_filename, &hstat);
  617.         if (check != 0) {
  618.             if (make_dirs(skipcrud+current_filename)) {
  619.             goto again_pdev;
  620.             }
  621.             msg_perror("Could not make pseudo device %s",
  622.             skipcrud+current_filename);
  623.             break;
  624.         }
  625.         goto set_filestat;
  626.  
  627.     case LF_RMTLINK:
  628.     again_rmtlink:
  629.         check = SpriteMakeRemoteLink(current_linkname,
  630.                          current_filename);
  631.         if (check != 0) {
  632.             if (make_dirs(skipcrud+current_filename)) {
  633.             goto again_rmtlink;
  634.             }
  635.             msg_perror("Could not create remote link %s", current_linkname);
  636.             break;
  637.         }
  638.         goto set_filestat;
  639.  
  640. #endif /* sprite */
  641.  
  642.     make_node:
  643.         check = mknod(skipcrud+current_filename,
  644.                   (int) hstat.st_mode, (int) hstat.st_rdev);
  645.         if (check != 0) {
  646.             if (make_dirs(skipcrud+current_filename))
  647.                 goto make_node;
  648.             msg_perror("Could not make %s",skipcrud+current_filename);
  649.             break;
  650.         };
  651.         goto set_filestat;
  652.  
  653.     case LF_DIR:
  654.     case LF_DUMPDIR:
  655.         namelen = strlen(skipcrud+current_filename)-1;
  656.     really_dir:
  657.         /* Check for trailing /, and zap as many as we find. */
  658.         while (namelen && current_filename[skipcrud+namelen] == '/')
  659.             current_filename[skipcrud+namelen--] = '\0';
  660.         if(f_gnudump) {        /* Read the entry and delete files
  661.                        that aren't listed in the archive */
  662.             gnu_restore(skipcrud+current_filename);
  663.  
  664.         } else if(head->header.linkflag==LF_DUMPDIR)
  665.             skip_file((long)(hstat.st_size));
  666.  
  667.  
  668.     again_dir:
  669.         check = mkdir(skipcrud+current_filename,
  670.                   0300 | (int)hstat.st_mode);
  671.         if (check != 0) {
  672. #ifdef ALLOW_NO_RECURSE
  673.                 if (f_no_recurse) {
  674.                 if (errno == ENOTDIR || errno == EEXIST) {
  675.                 /* check and see if it is a regular file. */
  676.                 struct stat buf;
  677.  
  678.                 if (stat(skipcrud+current_filename, &buf) != 0) {
  679.                     msg_perror("Could not stat %s",
  680.                     skipcrud+current_filename);
  681.                     break;
  682.                 }
  683.                 switch (buf.st_mode & S_IFMT) {
  684.  
  685.                 case S_IFDIR:
  686.                     break;
  687.  
  688.                 case S_IFREG:
  689.                     msg("Unlinking %s", skipcrud+current_filename);
  690.                     if (unlink(skipcrud+current_filename) == 0) {
  691.                     goto again_dir;
  692.                     }
  693.                     msg_perror("Could not unlink %s",
  694.                     skipcrud+current_filename);
  695.                     break;
  696.  
  697.                 default:
  698.                     msg("%s already exists");
  699.                     break;
  700.                 }
  701.                 break;
  702.                 }
  703.             }
  704. #endif
  705.             if (make_dirs(skipcrud+current_filename))
  706.                 goto again_dir;
  707.             /* If we're trying to create '.', let it be. */
  708.             if (current_filename[skipcrud+namelen] == '.' && 
  709.                 (namelen==0 ||
  710.                  current_filename[skipcrud+namelen-1]=='/'))
  711.                 goto check_perms;
  712.             if(f_gnudump && errno==EEXIST)
  713.                 break;
  714.             msg_perror("Could not make directory %s",skipcrud+current_filename);
  715.             break;
  716.         }
  717.  
  718.     check_perms:
  719.         if (0300 != (0300 & (int) hstat.st_mode)) {
  720.             hstat.st_mode |= 0300;
  721.             msg("Added write and execute permission to directory %s",
  722.               skipcrud+current_filename);
  723.         }
  724.  
  725.         goto set_filestat;
  726.         /* FIXME, Remember timestamps for after files created? */
  727.         /* FIXME, change mode after files created (if was R/O dir) */
  728.     case LF_VOLHDR:
  729.         if(f_verbose) {
  730.             printf("Reading %s\n",current_filename);
  731.         }
  732.         break;
  733.  
  734.     case LF_MULTIVOL:
  735.         msg("Can't extract '%s'--file is continued from another volume\n",current_filename);
  736.         skip_file((long)hstat.st_size);
  737.         break;
  738.  
  739.     }
  740.  
  741.     return;
  742. }
  743.  
  744. /*
  745.  * After a file/link/symlink/dir creation has failed, see if
  746.  * it's because some required directory was not present, and if
  747.  * so, create all required dirs.
  748.  */
  749. int
  750. make_dirs(pathname)
  751.     char *pathname;
  752. {
  753.     char *p;            /* Points into path */
  754.     int madeone = 0;        /* Did we do anything yet? */
  755.     int save_errno = errno;        /* Remember caller's errno */
  756.     int check;
  757.  
  758.     if (errno != ENOENT)
  759.         return 0;        /* Not our problem */
  760.  
  761.     for (p = index(pathname, '/'); p != NULL; p = index(p+1, '/')) {
  762.         /* Avoid mkdir of empty string, if leading or double '/' */
  763.         if (p == pathname || p[-1] == '/')
  764.             continue;
  765.         /* Avoid mkdir where last part of path is '.' */
  766.         if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
  767.             continue;
  768.         *p = 0;                /* Truncate the path there */
  769. again_dir:        
  770.         check = mkdir (pathname, 0777);    /* Try to create it as a dir */
  771.         if (check == 0) {
  772. #ifdef ALLOW_NO_RECURSE
  773.             if (f_no_recurse && errno == ENOTDIR) {
  774.             /* check and see if it is a regular file. */
  775.             struct stat buf;
  776.  
  777.             if (stat(pathname, &buf) != 0) {
  778.                 msg_perror("Could not stat %s", pathname);
  779.             } else if ((buf.st_mode & S_IFMT) == S_IFREG) {
  780.                 msg("Unlinking %s", pathname);
  781.                 if (unlink(pathname) == 0) {
  782.                 goto again_dir;
  783.                 }
  784.                 msg_perror("Could not unlink %s", pathname);
  785.             }
  786.             }
  787. #endif
  788.             /* Fix ownership */
  789.             if (we_are_root) {
  790.             if (chown(pathname, hstat.st_uid,
  791.                 hstat.st_gid) < 0) {
  792.                 msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
  793.                 }
  794.             }
  795.             pr_mkdir(pathname, p-pathname, notumask&0777);
  796.             madeone++;        /* Remember if we made one */
  797.             *p = '/';
  798.             continue;
  799.         }
  800.         *p = '/';
  801.         if (errno == EEXIST)        /* Directory already exists */
  802.             continue;
  803.         /*
  804.          * Some other error in the mkdir.  We return to the caller.
  805.          */
  806.         break;
  807.     }
  808.  
  809.     errno = save_errno;        /* Restore caller's errno */
  810.     return madeone;            /* Tell them to retry if we made one */
  811. }
  812.  
  813. extract_sparse_file(fd, sizeleft, totalsize, name)
  814.     int    fd;
  815.     long    *sizeleft,
  816.         totalsize;
  817.     char    *name;
  818. {        
  819.     register char    *data;
  820.     union record    *datarec;
  821.     int    sparse_ind = 0;
  822.     int    written,
  823.         count;
  824.  
  825.     /* assuming sizeleft is initially totalsize */
  826.  
  827.  
  828.     while (*sizeleft > 0) {
  829.         datarec = findrec();
  830.         if (datarec == NULL) {
  831.             msg("Unexpected EOF on archive file");
  832.             return;
  833.         }
  834.         lseek(fd, sparsearray[sparse_ind].offset, 0);
  835.         written = sparsearray[sparse_ind++].numbytes;
  836.         while (written > RECORDSIZE) {
  837.             count = write(fd, datarec->charptr, RECORDSIZE);
  838.             if (count < 0) 
  839.                 msg_perror("couldn't write to file %s", name);
  840.             written -= count;
  841.             *sizeleft -= count;
  842.             userec(datarec);
  843.             datarec = findrec();
  844.         }
  845.  
  846.         count = write(fd, datarec->charptr, written);
  847.  
  848.         if (count < 0) {
  849.             msg_perror("couldn't write to file %s", name);
  850.         } else if (count != written) {
  851.             msg("could only write %d of %d bytes to file %s", totalsize - *sizeleft, totalsize, name);
  852.             skip_file((long) (*sizeleft));
  853.         }
  854.  
  855.         written -= count;
  856.         *sizeleft -= count;        
  857.         userec(datarec);
  858.     
  859.     }
  860. /*    if (end_nulls) {
  861.         register int i;
  862.  
  863.         printf("%d\n", (int) end_nulls);
  864.         for (i = 0; i < end_nulls; i++)
  865.             write(fd, "\000", 1);
  866.     }*/
  867.     userec(datarec);
  868. }
  869. @
  870.  
  871.  
  872. 1.5
  873. log
  874. @Lint.
  875. @
  876. text
  877. @a86 3
  878. #ifdef ALLOW_LONG_NAMES
  879. extern char *get_long_name();
  880. #endif
  881. a140 2
  882.     char filename[MAXPATHLEN];
  883.     char linkname[MAXPATHLEN];
  884. a142 2
  885.     saverec(&head);            /* Make sure it sticks around */
  886.     userec(head);            /* And go past it in the archive */
  887. d145 2
  888. a146 12
  889. #ifdef ALLOW_LONG_NAMES
  890.     strcpy(filename, get_long_name(head, XH_FILENAME));
  891.     strcpy(linkname, get_long_name(head, XH_LINKNAME));
  892. #else
  893.     strcpy(filename, head->header.filename);
  894.     strcpy(linkname, head->header.linkname);
  895. #endif    
  896.     if (head->header.isextended & (XH_FILENAME | XH_LINKNAME)) {
  897.         skip_extended_headers();
  898.     }
  899.     if(f_confirm && !confirm("extract",filename)) {
  900.         if (head->header.isextended)
  901. a148 1
  902.         saverec((union record **)0);
  903. d165 1
  904. a165 1
  905.     while (!f_absolute_paths && '/' == filename[skipcrud]) {
  906. d179 1
  907. a179 1
  908.             head->header.linkflag, skipcrud+filename);
  909. d209 2
  910. a210 1
  911.         if (head->header.isextended & XH_SPARSE_FILE) {
  912. d258 2
  913. a259 2
  914.         namelen = strlen(skipcrud+filename)-1;
  915.         if (filename[skipcrud+namelen] == '/')
  916. d302 1
  917. a302 1
  918.             fd = open(skipcrud+filename, openflag | O_CTG,
  919. d312 1
  920. a312 1
  921.             fd = creat(skipcrud+filename, hstat.st_mode);
  922. d317 1
  923. a317 1
  924.             fd = open(skipcrud+filename, openflag, hstat.st_mode);
  925. d322 1
  926. a322 1
  927.             if (make_dirs(skipcrud+filename))
  928. d324 2
  929. a325 2
  930.             msg_perror("Could not create file %s",skipcrud+filename);
  931.             if (head->header.isextended)
  932. d343 2
  933. d346 1
  934. a346 1
  935.             namelen = strlen(skipcrud+filename);
  936. d348 1
  937. a348 1
  938.             bcopy(skipcrud+filename, name, namelen);
  939. a356 4
  940.  
  941.             long    offset,
  942.                  numbytes;
  943.  
  944. d358 1
  945. a358 1
  946.                 save_name=filename;
  947. d404 1
  948. a404 1
  949.                 msg_perror("couldn't write to file %s",skipcrud+filename);
  950. d406 1
  951. a406 1
  952.                 msg("could only write %d of %d bytes to file %s",written,check,skipcrud+filename);
  953. d420 1
  954. a420 1
  955. /*        if (head->header.isextended) {
  956. d443 1
  957. a443 1
  958.             msg_perror("Error while closing %s",skipcrud+filename);
  959. d456 1
  960. a456 1
  961.             if (chown(skipcrud+filename, hstat.st_uid,
  962. d458 1
  963. a458 1
  964.                 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+filename,hstat.st_uid,hstat.st_gid);
  965. d477 1
  966. a477 1
  967.             if (chmod(skipcrud+filename,
  968. d479 1
  969. a479 1
  970.                 msg_perror("cannot change mode of file %s to %ld",skipcrud+filename,notumask & (int)hstat.st_mode);
  971. d494 2
  972. a495 2
  973.             if (utime(skipcrud+filename, acc_upd_times) < 0) {
  974.                 msg_perror("couldn't change access and modification times of %s",skipcrud+filename);
  975. d504 1
  976. a504 1
  977.         check = link (linkname, skipcrud+filename);
  978. d507 1
  979. a507 1
  980.         if (make_dirs(skipcrud+filename))
  981. d512 1
  982. a512 1
  983.             skipcrud+filename,linkname);
  984. d518 2
  985. a519 2
  986.         check = symlink(linkname,
  987.                     skipcrud+filename);
  988. d523 1
  989. a523 1
  990.         if (make_dirs(skipcrud+filename))
  991. d525 1
  992. a525 1
  993.         msg_perror("Could not create symlink to %s",linkname);
  994. d546 1
  995. a546 1
  996.         check = SpriteMakeNamedPipe(head, hstat);
  997. d548 1
  998. a548 1
  999.             if (make_dirs(skipcrud+filename)) {
  1000. d552 1
  1001. a552 1
  1002.             skipcrud+filename);
  1003. d566 1
  1004. a566 1
  1005.         check = SpriteMakePseudoDev(head, &hstat);
  1006. d568 1
  1007. a568 1
  1008.             if (make_dirs(skipcrud+filename)) {
  1009. d572 1
  1010. a572 1
  1011.             skipcrud+filename);
  1012. d579 2
  1013. a580 2
  1014.         check = SpriteMakeRemoteLink(linkname,
  1015.                     filename);
  1016. d582 1
  1017. a582 1
  1018.             if (make_dirs(skipcrud+filename)) {
  1019. d585 1
  1020. a585 1
  1021.             msg_perror("Could not create remote link %s", linkname);
  1022. d593 1
  1023. a593 1
  1024.         check = mknod(skipcrud+filename,
  1025. d596 1
  1026. a596 1
  1027.             if (make_dirs(skipcrud+filename))
  1028. d598 1
  1029. a598 1
  1030.             msg_perror("Could not make %s",skipcrud+filename);
  1031. d605 1
  1032. a605 1
  1033.         namelen = strlen(skipcrud+filename)-1;
  1034. d608 2
  1035. a609 2
  1036.         while (namelen && filename[skipcrud+namelen] == '/')
  1037.             filename[skipcrud+namelen--] = '\0';
  1038. d612 1
  1039. a612 1
  1040.             gnu_restore(skipcrud+filename);
  1041. d619 1
  1042. a619 1
  1043.         check = mkdir(skipcrud+filename,
  1044. d628 1
  1045. a628 1
  1046.                 if (stat(skipcrud+filename, &buf) != 0) {
  1047. d630 1
  1048. a630 1
  1049.                     skipcrud+filename);
  1050. d639 2
  1051. a640 2
  1052.                     msg("Unlinking %s", skipcrud+filename);
  1053.                     if (unlink(skipcrud+filename) == 0) {
  1054. d644 1
  1055. a644 1
  1056.                     skipcrud+filename);
  1057. d655 1
  1058. a655 1
  1059.             if (make_dirs(skipcrud+filename))
  1060. d658 1
  1061. a658 1
  1062.             if (filename[skipcrud+namelen] == '.' && 
  1063. d660 1
  1064. a660 1
  1065.                  filename[skipcrud+namelen-1]=='/'))
  1066. d664 1
  1067. a664 1
  1068.             msg_perror("Could not make directory %s",skipcrud+filename);
  1069. d672 1
  1070. a672 1
  1071.               skipcrud+filename);
  1072. d680 1
  1073. a680 1
  1074.             printf("Reading %s\n",filename);
  1075. d685 1
  1076. a685 1
  1077.         msg("Can't extract '%s'--file is continued from another volume\n",filename);
  1078. a690 2
  1079.     /* We don't need to save it any longer. */
  1080.     saverec((union record **) 0);    /* Unsave it */
  1081. @
  1082.  
  1083.  
  1084. 1.4
  1085. log
  1086. @Mary checking this in for Jhh.
  1087. @
  1088. text
  1089. @d585 1
  1090. a585 1
  1091.         check = SpriteMakePseudoDev(head, hstat);
  1092. @
  1093.  
  1094.  
  1095. 1.3
  1096. log
  1097. @Non-recursive directory dumping.
  1098. @
  1099. text
  1100. @d282 10
  1101. d294 1
  1102. @
  1103.  
  1104.  
  1105. 1.2
  1106. log
  1107. @Added support for long filenames and long symbolic linkes.
  1108. @
  1109. text
  1110. @d631 30
  1111. a660 2
  1112.                 if (f_no_recurse && errno == EEXIST) {
  1113.                 break;
  1114. d729 1
  1115. d732 13
  1116. a744 6
  1117.             /* Fix ownership */
  1118.             if (we_are_root) {
  1119.                 if (chown(pathname, hstat.st_uid,
  1120.                       hstat.st_gid) < 0) {
  1121.                     msg_perror("cannot change owner of %s to uid %d gid %d",pathname,hstat.st_uid,hstat.st_gid);
  1122.                 }
  1123. d746 13
  1124. a758 4
  1125.             pr_mkdir(pathname, p-pathname, notumask&0777);
  1126.             madeone++;        /* Remember if we made one */
  1127.             *p = '/';
  1128.             continue;
  1129. d784 1
  1130. a784 1
  1131.     
  1132. d807 1
  1133. a807 1
  1134.             
  1135. @
  1136.  
  1137.  
  1138. 1.1
  1139. log
  1140. @Initial revision
  1141. @
  1142. text
  1143. @d32 1
  1144. d87 3
  1145. d144 3
  1146. a146 1
  1147.     
  1148. d152 11
  1149. a162 1
  1150.     if(f_confirm && !confirm("extract",head->header.name)) {
  1151. d183 1
  1152. a183 1
  1153.     while (!f_absolute_paths && '/' == head->header.name[skipcrud]) {
  1154. d197 1
  1155. a197 1
  1156.             head->header.linkflag, skipcrud+head->header.name);
  1157. d224 1
  1158. a224 1
  1159.         
  1160. d226 2
  1161. a227 2
  1162.         
  1163.         if (head->header.isextended) {
  1164. d233 1
  1165. a233 1
  1166.             
  1167. d235 1
  1168. a235 1
  1169.                 
  1170. d238 1
  1171. a238 1
  1172.                     
  1173. d243 1
  1174. a243 1
  1175.                       */
  1176. d246 1
  1177. a246 1
  1178.                                  2 * sp_array_size * (sizeof(struct sp_array)));
  1179. d249 1
  1180. a249 1
  1181.                     if (!exhdr->ext_hdr.sp[i].numbytes)
  1182. d252 1
  1183. a252 1
  1184.                         from_oct(1+12, exhdr->ext_hdr.sp[i].offset);
  1185. d254 1
  1186. a254 1
  1187.                         from_oct(1+12, exhdr->ext_hdr.sp[i].numbytes);
  1188. d256 1
  1189. a256 1
  1190.                 if (!exhdr->ext_hdr.isextended) 
  1191. d265 1
  1192. a265 1
  1193.         
  1194. d270 1
  1195. d275 2
  1196. a276 2
  1197.         namelen = strlen(skipcrud+head->header.name)-1;
  1198.         if (head->header.name[skipcrud+namelen] == '/')
  1199. d308 1
  1200. a308 1
  1201.             fd = open(skipcrud+head->header.name, openflag | O_CTG,
  1202. d318 1
  1203. a318 2
  1204.             fd = creat(skipcrud+head->header.name, 
  1205.                 hstat.st_mode);
  1206. d323 1
  1207. a323 2
  1208.             fd = open(skipcrud+head->header.name, openflag,
  1209.                 hstat.st_mode);
  1210. d328 1
  1211. a328 1
  1212.             if (make_dirs(skipcrud+head->header.name))
  1213. d330 1
  1214. a330 1
  1215.             msg_perror("Could not create file %s",skipcrud+head->header.name);
  1216. d350 1
  1217. a350 1
  1218.             namelen = strlen(skipcrud+head->header.name);
  1219. d352 1
  1220. a352 1
  1221.             bcopy(skipcrud+head->header.name, name, namelen);
  1222. d366 1
  1223. a366 1
  1224.                 save_name=head->header.name;
  1225. d412 1
  1226. a412 1
  1227.                 msg_perror("couldn't write to file %s",skipcrud+head->header.name);
  1228. d414 1
  1229. a414 1
  1230.                 msg("could only write %d of %d bytes to file %s",written,check,skipcrud+head->header.name);
  1231. d431 1
  1232. a431 1
  1233.             
  1234. d434 1
  1235. a434 1
  1236.                 
  1237. d438 1
  1238. a438 1
  1239.                          exhdr->ext_hdr.sp[i].offset);
  1240. d440 1
  1241. a440 1
  1242.                          exhdr->ext_hdr.sp[i].numbytes);
  1243. d446 1
  1244. a446 1
  1245.             
  1246. d449 1
  1247. a449 1
  1248.          check = close(fd);
  1249. d451 1
  1250. a451 1
  1251.             msg_perror("Error while closing %s",skipcrud+head->header.name);
  1252. d454 1
  1253. a454 1
  1254.         
  1255. d464 1
  1256. a464 1
  1257.             if (chown(skipcrud+head->header.name, hstat.st_uid,
  1258. d466 1
  1259. a466 1
  1260.                 msg_perror("cannot chown file %s to uid %d gid %d",skipcrud+head->header.name,hstat.st_uid,hstat.st_gid);
  1261. d485 1
  1262. a485 1
  1263.             if (chmod(skipcrud+head->header.name,
  1264. d487 1
  1265. a487 1
  1266.                 msg_perror("cannot change mode of file %s to %ld",skipcrud+head->header.name,notumask & (int)hstat.st_mode);
  1267. d502 2
  1268. a503 3
  1269.             if (utime(skipcrud+head->header.name,
  1270.                 acc_upd_times) < 0) {
  1271.                 msg_perror("couldn't change access and modification times of %s",skipcrud+head->header.name);
  1272. d512 1
  1273. a512 2
  1274.         check = link (head->header.linkname,
  1275.                   skipcrud+head->header.name);
  1276. d515 1
  1277. a515 1
  1278.         if (make_dirs(skipcrud+head->header.name))
  1279. d520 1
  1280. a520 1
  1281.             skipcrud+head->header.name,head->header.linkname);
  1282. d526 2
  1283. a527 2
  1284.         check = symlink(head->header.linkname,
  1285.                     skipcrud+head->header.name);
  1286. d531 1
  1287. a531 1
  1288.         if (make_dirs(skipcrud+head->header.name))
  1289. d533 1
  1290. a533 1
  1291.         msg_perror("Could not create symlink to %s",head->header.linkname);
  1292. d551 14
  1293. a564 1
  1294.     case LF_FIFO:
  1295. d568 31
  1296. a598 1
  1297. #endif
  1298. d601 1
  1299. a601 1
  1300.         check = mknod(skipcrud+head->header.name,
  1301. d604 1
  1302. a604 1
  1303.             if (make_dirs(skipcrud+head->header.name))
  1304. d606 1
  1305. a606 1
  1306.             msg_perror("Could not make %s",skipcrud+head->header.name);
  1307. d613 1
  1308. a613 1
  1309.         namelen = strlen(skipcrud+head->header.name)-1;
  1310. d616 2
  1311. a617 2
  1312.         while (namelen && head->header.name[skipcrud+namelen] == '/')
  1313.             head->header.name[skipcrud+namelen--] = '\0';
  1314. d620 2
  1315. a621 2
  1316.             gnu_restore(skipcrud+head->header.name);
  1317.         
  1318. d625 1
  1319. a625 1
  1320.     
  1321. d627 1
  1322. a627 1
  1323.         check = mkdir(skipcrud+head->header.name,
  1324. d630 6
  1325. a635 1
  1326.             if (make_dirs(skipcrud+head->header.name))
  1327. d638 1
  1328. a638 1
  1329.             if (head->header.name[skipcrud+namelen] == '.' && 
  1330. d640 1
  1331. a640 1
  1332.                  head->header.name[skipcrud+namelen-1]=='/'))
  1333. d644 1
  1334. a644 1
  1335.             msg_perror("Could not make directory %s",skipcrud+head->header.name);
  1336. d647 1
  1337. a647 1
  1338.         
  1339. d652 1
  1340. a652 1
  1341.               skipcrud+head->header.name);
  1342. d660 1
  1343. a660 1
  1344.             printf("Reading %s\n",head->header.name);
  1345. d665 1
  1346. a665 1
  1347.         msg("Can't extract '%s'--file is continued from another volume\n",head->header.name);
  1348. d673 1
  1349. @
  1350.